<i18n locale="en" lang="yaml">
direct     : Directly Call
integration: Integration Call
syncAPI    : Sync API
asyncAPI   : Async API
cronJob    : Cron Job
connector  : Connector

'Func ID: '        : 'Func ID   : '
'Func Title: '     : 'Func Title: '
'Blueprint ID: '   : 'Blueprint ID   : '
'Blueprint Title: ': 'Blueprint Title: '

'Queue: '       : 'Queue       : '
'Trigger Time: ': 'Trigger Time: '
'Start Time: '  : 'Start Time  : '
'End Time: '    : 'End Time    : '
'Delay Time: '  : 'Delay Time  : '
'Queuing Time: ': 'Queuing Time: '
'Task Timeout: ': 'Task Timeout: '
'Task Expires: ': 'Task Expires: '
'Run Cost: '    : 'Run Cost    : '
'Task Type: '   : 'Task Type   : '
'Task Status: ' : 'Task Status : '
</i18n>
<i18n locale="zh-CN" lang="yaml">
Exec Mode          : 执行模式
Trigger Time       : 触发时间
Task               : 任务
Func ID            : 函数 ID
Main Task          : 主任务
Sub Task           : 子任务
Delay              : 延迟
Queuing            : 排队
Wait Cost          : 等待耗时
Run Cost           : 执行耗时
Log Lines          : 日志行数
Print Log          : Print 日志
Traceback          : 调用堆栈
No Print Log       : 无 Print 日志
Non-critical Errors: 非关键错误

Recent Task Record        : 近期任务记录
Related Task Record       : 相关任务记录
Only main tasks are listed: 在本页面只展示主任务

success: 成功
failure: 失败
timeout: 执行超时
skip   : 跳过执行

Main Task Only: 仅主任务
Show Detail   : 显示详情
Related Tasks : 相关任务

Task Record cleared: 任务记录已清空

Are you sure you want to clear the Task Record?: 是否确认清空任务记录？

Non-critical errors exist                              : 存在非关键错误
Guance Data Upload Failed                              : 观测云数据上报失败
No Recent Task Record                                  : 尚无任何近期任务记录
All recent Task Record will be collected and shown here: 所有近期任务会被记录，并展示在此

Origin   : 来源
Origin ID: 来源 ID

direct     : 直接调用
integration: 集成调用
syncAPI    : 同步 API
asyncAPI   : 异步 API
cronJob    : 定时任务
connector  : 连接器

'Func ID: '        : '函数 ID ：'
'Func Title: '     : '函数标题：'
'Blueprint ID: '   : '蓝图 ID ：'
'Blueprint Title: ': '蓝图标题：'
'Queue: '          : '执行队列：'

'Trigger Time: '   : '触发时间：'
'Start Time: '     : '开始时间：'
'End Time: '       : '结束时间：'
'Task Timeout: '   : '任务超时：'
'Task Expires: '   : '任务过期：'
'Delay Time: '     : '延迟执行：'
'Queuing Time: '   : '排队等待：'
'Run Cost: '       : '执行耗时：'
'Task Type: '      : '任务类型：'
'Task Status: '    : '任务状态：'

'No Delay': '不延迟'
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
All recent Task Record will be collected and shown here: 所有近期任務會被記錄，並展示在此
Are you sure you want to clear the Task Record?: 是否確認清空任務記錄？
'Blueprint ID: ': 藍圖 ID ：
'Blueprint Title: ': 藍圖標題：
Delay: 延遲
'Delay Time: ': 延遲執行：
'End Time: ': 結束時間：
Exec Mode: 執行模式
Func ID: 函數 ID
'Func ID: ': 函數 ID ：
'Func Title: ': 函數標題：
Guance Data Upload Failed: 觀測雲數據上報失敗
Log Lines: 日誌行數
Main Task: 主任務
Main Task Only: 僅主任務
No Delay: 不延遲
No Print Log: 無 Print 日誌
No Recent Task Record: 尚無任何近期任務記錄
Non-critical Errors: 非關鍵錯誤
Non-critical errors exist: 存在非關鍵錯誤
Only main tasks are listed: 在本頁面只展示主任務
Origin: 來源
Origin ID: 來源 ID
Print Log: Print 日誌
'Queue: ': 執行隊列：
Queuing: 排隊
'Queuing Time: ': 排隊等待：
Recent Task Record: 近期任務記錄
Related Task Record: 相關任務記錄
Related Tasks: 相關任務
Run Cost: 執行耗時
'Run Cost: ': 執行耗時：
Show Detail: 顯示詳情
'Start Time: ': 開始時間：
Sub Task: 子任務
Task: 任務
'Task Expires: ': 任務過期：
Task Record cleared: 任務記錄已清空
'Task Status: ': 任務狀態：
'Task Timeout: ': 任務超時：
'Task Type: ': 任務類型：
Traceback: 調用堆棧
Trigger Time: 觸發時間
'Trigger Time: ': 觸發時間：
Wait Cost: 等待耗時
asyncAPI: 異步 API
connector: 連接器
cronJob: 定時任務
direct: 直接調用
failure: 失敗
integration: 集成調用
skip: 跳過執行
success: 成功
syncAPI: 同步 API
timeout: 執行超時
</i18n>
<i18n locale="zh-TW" lang="yaml">
All recent Task Record will be collected and shown here: 所有近期任務會被記錄，並展示在此
Are you sure you want to clear the Task Record?: 是否確認清空任務記錄？
'Blueprint ID: ': 藍圖 ID ：
'Blueprint Title: ': 藍圖示題：
Delay: 延遲
'Delay Time: ': 延遲執行：
'End Time: ': 結束時間：
Exec Mode: 執行模式
Func ID: 函式 ID
'Func ID: ': 函式 ID ：
'Func Title: ': 函式標題：
Guance Data Upload Failed: 觀測雲資料上報失敗
Log Lines: 日誌行數
Main Task: 主任務
Main Task Only: 僅主任務
No Delay: 不延遲
No Print Log: 無 Print 日誌
No Recent Task Record: 尚無任何近期任務記錄
Non-critical Errors: 非關鍵錯誤
Non-critical errors exist: 存在非關鍵錯誤
Only main tasks are listed: 在本頁面只展示主任務
Origin: 來源
Origin ID: 來源 ID
Print Log: Print 日誌
'Queue: ': 執行佇列：
Queuing: 排隊
'Queuing Time: ': 排隊等待：
Recent Task Record: 近期任務記錄
Related Task Record: 相關任務記錄
Related Tasks: 相關任務
Run Cost: 執行耗時
'Run Cost: ': 執行耗時：
Show Detail: 顯示詳情
'Start Time: ': 開始時間：
Sub Task: 子任務
Task: 任務
'Task Expires: ': 任務過期：
Task Record cleared: 任務記錄已清空
'Task Status: ': 任務狀態：
'Task Timeout: ': 任務超時：
'Task Type: ': 任務型別：
Traceback: 呼叫堆疊
Trigger Time: 觸發時間
'Trigger Time: ': 觸發時間：
Wait Cost: 等待耗時
asyncAPI: 非同步 API
connector: 聯結器
cronJob: 定時任務
direct: 直接呼叫
failure: 失敗
integration: 整合呼叫
skip: 跳過執行
success: 成功
syncAPI: 同步 API
timeout: 執行超時
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <transition name="fade">
    <el-container direction="vertical" v-show="$store.state.isLoaded">
      <!-- Header area -->
      <el-header height="60px">
        <div class="common-page-header">
          <div>
            <h1>{{ isRoot ? $t('Recent Task Record') : $t('Related Task Record') }}</h1>
            <small class="text-info">
              &#12288;
              <span class="filter-item" v-if="dataFilter.origin">
                {{ $t('Origin')}}
                <code class="text-main">{{ $t(dataFilter.origin) }}</code>
              </span>
              <span class="filter-item" v-if="dataFilter.originId">
                {{ $t('Origin ID')}}
                <code class="text-main">{{ dataFilter.originId }}</code>
                <CopyButton :content="dataFilter.originId" />
              </span>
              <span class="filter-item" v-if="dataFilter.funcId">
                {{ $t('Func ID')}}
                <code class="text-main">{{ dataFilter.funcId }}</code>
                <CopyButton :content="dataFilter.funcId" />
              </span>
            </small>
          </div>

          <div class="header-control">
            <FuzzySearchInput :dataFilter="dataFilter"></FuzzySearchInput>

            <el-tooltip :content="$t('Only main tasks are listed')" placement="bottom" :enterable="false" v-if="hasTaskType">
              <el-checkbox v-if="isRoot"
                :border="true"
                size="small"
                v-model="dataFilter.rootTaskId"
                true-label="ROOT"
                false-label=""
                @change="T.changePageFilter(dataFilter)">{{ $t('Main Task Only') }}</el-checkbox>
            </el-tooltip>
          </div>
        </div>
      </el-header>

      <!-- List area -->
      <el-main class="common-table-container">
        <div class="no-data-area" v-if="T.isNothing(data)">
          <h1 class="no-data-title" v-if="T.isPageFiltered()"><i class="fa fa-fw fa-search"></i>{{ $t('No matched data found') }}</h1>
          <h1 class="no-data-title" v-else><i class="fa fa-fw fa-info-circle"></i>{{ $t('No Recent Task Record') }}</h1>

          <p class="no-data-tip">
            {{ $t('All recent Task Record will be collected and shown here') }}
          </p>
        </div>
        <el-table v-else
          class="common-table" height="100%"
          :data="data"
          :row-class-name="common.getHighlightRowCSS">

          <el-table-column :label="$t('Status')" width="120">
            <template slot-scope="scope">
              <el-tag
                v-if="C.TASK_STATUS_MAP.get(scope.row.status)"
                :type="C.TASK_STATUS_MAP.get(scope.row.status).tagType"><i :class="C.TASK_STATUS_MAP.get(scope.row.status).icon"></i>
                {{ C.TASK_STATUS_MAP.get(scope.row.status).name }}
              </el-tag>
            </template>
          </el-table-column>

          <el-table-column :label="$t('Trigger Time')" width="200">
            <template slot-scope="scope">
              <span>{{ scope.row.triggerTimeMs | datetime }}</span>
              <br>
              <span class="text-info">{{ scope.row.triggerTimeMs | toNow }}</span>
            </template>
          </el-table-column>

          <el-table-column width="100" align="center" v-if="hasTaskType">
            <template slot-scope="scope">
              <el-tag v-if="scope.row.subTaskCount > 0" size="medium" type="primary">{{ $t('Main Task') }}</el-tag>
              <el-tag v-else-if="scope.row.rootTaskId !== 'ROOT'" size="small" type="info">{{ $t('Sub Task') }}</el-tag>
            </template>
          </el-table-column>

          <el-table-column :label="$t('Func')" min-width="300">
            <template slot-scope="scope">
              <FuncInfo
                :config-func-id="scope.row.funcId"
                :id="scope.row.func_id"
                :title="scope.row.func_title" />
              <InfoBlock v-if="scope.row.exceptionType" type="error" :title="`${scope.row.exceptionType}: ${scope.row.exceptionTEXT}`" />
              <InfoBlock v-if="scope.row.nonCriticalErrorsTEXT" type="warning" :title="`${$t('Non-critical errors exist')}${$t(':')}${getNonCriticalErrorSumary(scope.row)}`" />
            </template>
          </el-table-column>

          <el-table-column :label="$t('Wait Cost')" align="left" width="180">
            <template slot-scope="scope">
              <span class="text-info">{{ $t('Delay') }}{{ $t(':') }}</span>
              <template v-if="scope.row.delay">
                <span class="text-main">
                  <TimeDuration :duration="scope.row.delay" unit="s" />
                </span>
              </template>
              <template v-else>
                <span class="text-info">{{ $t('No Delay') }}</span>
              </template>

              <br>
              <span class="text-info">{{ $t('Queuing') }}{{ $t(':') }}</span>
              <span :class="scope.row.waitCostClass">
                <TimeDuration :duration="scope.row.queuingTime" unit="ms" />
              </span>
            </template>
          </el-table-column>
          <el-table-column :label="$t('Run Cost')" align="right" width="100">
            <template slot-scope="scope">
              <template v-if="scope.row.runCostMs">
                <TimeDuration :duration="scope.row.runCostMs" unit="ms" />
              </template>
              <template v-else>-</template>
            </template>
          </el-table-column>
          <el-table-column :label="$t('Log Lines')" align="right" width="100">
            <template slot-scope="scope">
              <strong v-if="scope.row.logLines < 10" class="text-info">{{ scope.row.logLines }}</strong>
              <strong v-else-if="scope.row.logLines < 100" class="text-good">{{ scope.row.logLines }}</strong>
              <strong v-else-if="scope.row.logLines < 1000" class="text-watch">{{ scope.row.logLines }}</strong>
              <strong v-else="scope.row.logLines" class="text-bad">{{ scope.row.logLines }}</strong>
            </template>
          </el-table-column>

          <el-table-column width="240" align="right">
            <template slot-scope="scope">
              <template v-if="isRoot">
                <el-button v-if="scope.row.subTaskCount > 0 || scope.row.rootTaskId !== 'ROOT'"
                  type="text"
                  @click="openSubTaskRecord(scope.row)"
                  >{{ $t('Related Tasks') }}</el-button>
              </template>

              <el-button @click="showDetail(scope.row)" type="text">{{ $t('Show Detail') }}</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-main>

      <!-- Paging area -->
      <Pager :pageInfo="pageInfo" />

      <LongTextDialog ref="longTextDialog" :showDownload="true" />
    </el-container>
  </transition>
</template>

<script>
import TimeDuration from '@/components/TimeDuration'
import LongTextDialog from '@/components/LongTextDialog'

export default {
  name: 'TaskRecordFuncList',
  components: {
    TimeDuration,
    LongTextDialog,
  },
  watch: {
    $route: {
      immediate: true,
      async handler(to, from) {
        await this.loadData();
      }
    },
    '$store.state.isLoaded': function(val) {
      if (!val) return;

      setImmediate(() => this.T.autoScrollTable());
    },
  },
  methods: {
    async loadData() {
      let _listQuery = this.dataFilter = this.T.createListQuery();
      let apiRes = await this.T.callAPI_get('/api/v1/task-records/func/do/list', {
        query: _listQuery,
      });
      if (!apiRes || !apiRes.ok) return;

      // Sort in descending order by trigger time (this is for front-end viewing only; the DB side is not suitable for sorting based on trigger time)
      apiRes.data.sort(function(a, b) {
        if (a.triggerTimeMs < b.triggerTimeMs) return 1;
        else if (a.triggerTimeMs > b.triggerTimeMs) return -1;
        else return 0;
      });

      apiRes.data.forEach(d => {
        // Check if there is a parent or child task.
        if (d.subTaskCount > 0 || d.rootTaskId !== 'ROOT') {
          this.hasTaskType = true;
        }

        // Log lines
        d.logLines = 0
        if (d.printLogsTEXT) {
          d.logLines = d.printLogsTEXT.split('\n').length;
        }

        // Wait cost
        if (d.triggerTimeMs && d.startTimeMs) {
          d.queuingTime = Math.max(0, d.startTimeMs - d.triggerTimeMs - (d.delay * 1000));

          if (d.queuingTime > 3 * 60 * 1000) {
            d.waitCostClass = 'text-bad';
          } else if (d.queuingTime > 10 * 1000) {
            d.waitCostClass = 'text-watch';
          } else if (d.queuingTime > 300) {
            d.waitCostClass = 'text-good';
          } else {
            d.waitCostClass = 'text-info';
          }
        }

        // Run cost
        if (d.startTimeMs && d.endTimeMs) {
          d.runCostMs = d.endTimeMs - d.startTimeMs;

          if (d.runCostMs > 5 * 60 * 1000) {
            d.runCostClass = 'text-bad';
          } else if (d.runCostMs > 10 * 1000) {
            d.runCostClass = 'text-watch';
          } else {
            d.runCostClass = 'text-good';
          }
        }
      });

      this.data = apiRes.data;
      this.pageInfo = apiRes.pageInfo;

      this.$store.commit('updateLoadStatus', true);
    },
    openSubTaskRecord(d) {
      let nextRouteQuery = this.T.packRouteQuery();
      nextRouteQuery.filter = this.T.createPageFilter({
        rootTaskId: d.rootTaskId === 'ROOT' ? d.id : d.rootTaskId,
      })

      this.$store.commit('updateHighlightedTableDataId', d.id);
      this.$store.commit('updateTableList_scrollY');

      this.$router.push({
        name  : 'sub-task-record-func-list',
        params: { id: this.$route.params.id },
        query : nextRouteQuery,
      });
    },
    showDetail(d) {
      this.$store.commit('updateHighlightedTableDataId', d.id);

      let origin = 'scriptLib';
      let id     = d.funcId;
      if (this.T.startsWith(d.funcId, '_bp_')) {
        origin = 'blueprint';
        id     = d.funcId.replace(/^_bp_/g, '').split('__')[0];
      }

      let lines = [];
      lines.push(`===== ${this.$t('Task')} =====`);
      if (origin === 'scriptLib') {
        // Script
        lines.push(`${this.$t('Func ID: ')}${this.$t(id)}`);
        lines.push(`${this.$t('Func Title: ')}${this.$t(d.func_title)}`);
      } else {
        // Blueprint
        lines.push(`${this.$t('Blueprint ID: ')}${this.$t(id)}`);
        lines.push(`${this.$t('Blueprint Title: ')}${this.$t(d.func_title)}`);
      }

      lines.push('');

      // Queue
      lines.push(`${this.$t('Queue: ')}#${d.queue}`);

      // Task type
      lines.push(`${this.$t('Task Type: ')}${d.rootTaskId === 'ROOT' ? this.$t('Main Task') : this.$t('Sub Task')}`);

      // Task timeout / expires
      lines.push(`${this.$t('Task Timeout: ')}${d.timeout} ${this.$t('s')}`);
      lines.push(`${this.$t('Task Expires: ')}${d.expires} ${this.$t('s')}`);

      // Trigger / Start / End time
      lines.push(`${this.$t('Trigger Time: ')}${this.T.getDateTimeString(d.triggerTimeMs)} ${this.$t('(')}${this.T.toNow(d.triggerTimeMs)}${this.$t(')')}`);
      lines.push(`${this.$t('Start Time: ')}${this.T.getDateTimeString(d.startTimeMs)} ${this.$t('(')}${this.T.toNow(d.startTimeMs)}${this.$t(')')}`);
      lines.push(`${this.$t('End Time: ')}${this.T.getDateTimeString(d.endTimeMs)} ${this.$t('(')}${this.T.toNow(d.endTimeMs)}${this.$t(')')}`);

      // Delay
      if (d.delay > 0) {
        lines.push(`${this.$t('Delay Time: ')}${d.delay} ${this.$t('s')}`);
      } else {
        lines.push(`${this.$t('Delay Time: ')}-`);
      }

      // Queuing time / Run cost
      lines.push(`${this.$t('Queuing Time: ')}${d.queuingTime} ${this.$t('ms')}`);
      lines.push(`${this.$t('Run Cost: ')}${d.runCostMs} ${this.$t('ms')}`);

      // Task status
      lines.push(`${this.$t('Task Status: ')}${this.$t(d.status)}`);

      // Log
      lines.push('');
      lines.push(`===== ${this.$t('Print Log')} =====`);
      if (d.printLogsTEXT) {
        lines.push(d.printLogsTEXT);
      } else {
        lines.push(this.$t('No Print Log'));
      }

      // Traceback
      if (d.tracebackTEXT) {
        lines.push('');
        lines.push(`===== ${this.$t('Traceback')} =====`);
        lines.push(d.tracebackTEXT);
      }

      // Non-critical errors
      if (d.nonCriticalErrorsTEXT) {
        lines.push('');
        lines.push(`===== ${this.$t('Non-critical Errors')} =====`);
        lines.push(d.nonCriticalErrorsTEXT);
      }

      let docTEXT = lines.join('\n');

      let createTimeStr = this.M(d.createTime).format('YYYYMMDD_HHmmss');
      let fileName = `task-record.${origin}-${id}.log.${createTimeStr}`;
      this.$refs.longTextDialog.update(docTEXT, fileName);
    },
    getNonCriticalErrorSumary(d) {
      if (!d.nonCriticalErrorsTEXT) return '';

      let summary = [];
      if (d.nonCriticalErrorsTEXT.indexOf('[Guance Data Upload Errors]') >= 0) {
        summary.push(this.$t('Guance Data Upload Failed'))
      }

      return summary.join(this.$t(','));
    },
  },
  computed: {
    isRoot() {
      return this.$route.name === 'task-record-func-list';
    },
  },
  props: {
  },
  data() {
    let _pageInfo   = this.T.createPageInfo();
    let _dataFilter = this.T.createListQuery();

    return {
      data    : [],
      pageInfo: _pageInfo,

      dataFilter: {
        _fuzzySearch: _dataFilter._fuzzySearch,
        rootTaskId  : _dataFilter.rootTaskId,
      },

      hasTaskType: false,
    }
  },
}
</script>

<style scoped>
.filter-item + .filter-item:before {
  content: "|";
  position: relative;
  left: -6px;
}
.filter-item + .filter-item {
  margin-left: 10px;
}
.func-title {
  font-size: 16px;
}
.text-data {
  font-size: 14px;
  line-height: 1.5;
  margin: 0;
  color: grey;
}
</style>

<style>
</style>
